#include <iostream>
#include <cstdio>
#include <cassert>
#include <ctime>
#include <unistd.h>
#include <vector>
#include <string>
#include <sys/types.h>
#include <sys/wait.h>

using namespace std;

#define MakeSeed() srand(time(nullptr) ^ getpid() % 1234)
#define PROCESS_NUM 5
typedef void(*func_t)();

void downLoadTask()
{
    std::cout << getpid() << ": 下载任务\n" << std::endl;
    sleep(1);
}

void ioTask()
{
    std::cout << getpid() << ": IO任务\n" << std::endl;
    sleep(1);
}

void flushTask()
{
    std::cout << getpid() << ": 刷新任务\n" << std::endl;
    sleep(1);
}

void loadTaskFunc(vector<func_t>* funcMap)
{
    assert(funcMap);
    funcMap->push_back(downLoadTask);
    funcMap->push_back(ioTask);
    funcMap->push_back(flushTask);
}

class subEp
{
public:
    subEp(pid_t subId, int writeFd)
    :_subId(subId)
    ,_writeFd(writeFd)
    {
        char buffer[1024];
        snprintf(buffer, sizeof buffer, "process-%d[pid(%d)-fd(%d)]", _num++, _subId, _writeFd);
        _name = buffer;
    }
public:
    static int _num;
    string _name;
    pid_t _subId;
    int _writeFd;
};
//静态变量，类内声明，类外定义
int subEp::_num = 1;

//子进程从共享管道中读取任务
int recvTask(int readFd)
{
    int code = 0;
    ssize_t s = read(readFd, &code, sizeof(code));
    if (s == 4)
        return code;
    else
        return -1;
}

void createSubProcess(vector<subEp>* subs, vector<func_t>& funcMap)
{
    vector<int> deleteFd;
    for(int i = 0; i < PROCESS_NUM; ++i)
    {
        //创建管道文件
        int fds[2];
        int n = pipe(fds);
        assert(n == 0);
        //创建子进程
        pid_t id = fork();
        if(id == 0)
        {
            //关闭继承父进程的其他写入端
            for(int i = 0; i < deleteFd.size(); ++i)
            {
                close(deleteFd[i]);
            }
            //子进程
            //需要子进程进行读，所以关闭写
            close(fds[1]);
            //子进程进行任务处理
            while(1)
            {
                //1.获取命令码，如果没有发送，应该阻塞等待
                //从对应的共享资源中读取命令
                int commandCode = recvTask(fds[0]);
                //2.完成任务
                if(commandCode >= 0 && commandCode < funcMap.size())
                {
                    funcMap[commandCode]();
                }
                else if(commandCode == -1)
                {
                    break;
                }
            }
            exit(0);
        }
        //父进程
        //需要父进程写，所以关闭读
        close(fds[0]);
        //走到这里就有了子进程的id，还有父进程对应子进程的写入端fd；
        subEp sub(id, fds[1]);
        subs->push_back(sub);
        deleteFd.push_back(fds[1]);
    }
}

void sendTask(const subEp& process, int taskIdx)
{
    cout << "send task num: " << taskIdx << " send to -> " << process._name << endl;
    int n = write(process._writeFd, &taskIdx, sizeof(taskIdx));
    assert(n == sizeof(int));
}

void loadBlanceContrl(vector<subEp> subs, vector<func_t> funcMap, int count)
{
    bool forever = (count == 0 ? true : false);
    int subProcessNum = subs.size();
    int taskNum = funcMap.size();

    while(1)
    {
        sleep(1);
        //1.选择一个子进程
        int subIdx = rand() % subProcessNum;
        //2.选择一个任务
        int taskIdx = rand() % taskNum;
        //3.将任务发送给子进程
        sendTask(subs[subIdx], taskIdx);
        if(!forever)
        {
            --count;
            if(count == 0)
            {
                break;
            }
        }
    }
    //发送结束，关闭发送端
    for(int i = 0; i < subProcessNum; ++i)
    {
        close(subs[i]._writeFd);
    }
}

void waitProcess(vector<subEp> subs)
{
    for(int i = 0; i < subs.size(); ++i)\
    {
        waitpid(subs[i]._subId, nullptr, 0);
        cout << "wait sub process success ...: " << subs[i]._subId << endl;
    }
}

int main()
{
    MakeSeed();
    // 1. 建立子进程并建立和子进程通信的信道
    // 1.1 加载方发表
    vector<func_t> funcMap;
    loadTaskFunc(&funcMap);
    // 1.2 创建子进程，并且维护好父子通信信道
    vector<subEp> subs;
    createSubProcess(&subs, funcMap);

    // 2. 走到这里就是父进程, 控制子进程，负载均衡的向子进程发送命令码
    int taskCnt = 10; // 0: 永远进行
    loadBlanceContrl(subs, funcMap, taskCnt);

    // 3. 回收子进程信息
    waitProcess(subs);

    return 0;
}